/*
 * Copyright (c) 2001-2021 GuaHao.com Corporation Limited. All rights reserved.
 * This software is the confidential and proprietary information of GuaHao Company.
 * ("Confidential Information").
 * You shall not disclose such Confidential Information and shall use it only
 * in accordance with the terms of the license agreement you entered into with GuaHao.com.
 */
package com.test;


import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.annotation.ExcelProperty;
import com.alibaba.excel.annotation.write.style.ColumnWidth;
import com.alibaba.excel.annotation.write.style.ContentRowHeight;
import com.alibaba.excel.annotation.write.style.HeadFontStyle;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.sun.javadoc.ClassDoc;
import com.sun.javadoc.MethodDoc;
import com.sun.javadoc.RootDoc;

import java.io.File;
import java.util.Arrays;

/**
 * detail: JavaDoc 读取类
 *
 * @author Ttt
 */
public final class JavaDocReader {

    private JavaDocReader() {
    }

    // Doc 信息临时存储
    private static RootDoc mRoot;

    /**
     * detail: 一个简单 Doclet, 收到 RootDoc 对象保存起来供后续使用
     *
     * @author Ttt
     */
    public static class Doclet {

        public Doclet() {
        }

        /**
         * Doclet 中, 方法 start 必须为静态
         *
         * @param root {@link RootDoc}
         * @return true
         */
        public static boolean start(final RootDoc root) {
            mRoot = root;
            return true;
        }
    }

    // =============
    // = 回调通知接口 =
    // =============

    /**
     * detail: 读取回调
     *
     * @author Ttt
     */
    public interface Callback {

        /**
         * 回调通知
         *
         * @param path      文件路径
         * @param className 文件名 ( 类名 )
         * @param rootDoc   根 Doc 信息
         * @param classDocs 类 Doc 信息
         * @return 处理后的文档信息
         */
        String callback(String path, String className, RootDoc rootDoc, ClassDoc[] classDocs);

        /**
         * 异常回调
         *
         * @param e 异常信息
         */
        void error(Exception e);
    }

    // ==========
    // = 读取处理 =
    // ==========

    /**
     * 读取处理
     *
     * @param callback  读取回调
     * @param path      文件路径
     * @param className 文件名 ( 类名 )
     * @return 处理后的文档信息
     */
    private static String read(final Callback callback, final String path, final String className) {
        // 类 Doc 信息
        ClassDoc[] classDocs = null; // 如果有内部类, 则长度大于 1, 否则为 1 ( 指定的 className)
        // 防止为 null
        if (mRoot != null) {
            classDocs = mRoot.classes();
        }
        // 触发回调
        if (callback != null) {
            return callback.callback(path, className, mRoot, classDocs);
        }
        return null;
    }

    // =============
    // = 对外提供方法 =
    // =============

    /**
     * 读取文档处理
     *
     * @param callback      读取回调
     * @param path          文件路径
     * @param className     文件名 ( 类名 )
     * @param executeParams 执行参数
     * @return 处理后的文档信息
     */
    public static String readDoc(final Callback callback, final String path, final String className,
                                 final String[] executeParams) {
        try {
            // 调用 com.sun.tools.javadoc.Main 执行 javadoc, 具体参数百度搜索
            com.sun.tools.javadoc.Main.execute(executeParams);
            // 进行读取
            return read(callback, path, className);
        } catch (Exception e) {
            if (callback != null) {
                callback.error(e);
            }
        }
        return null;
    }

    // =

    /**
     * 创建执行参数
     * <pre>
     *     根据自己的需求创建, 对应需要的执行参数
     *     该方法, 主要是示范, 并且自用
     * </pre>
     *
     * @param readAll   是否读取全部 (-private 显示所有类和成员 )
     * @param path      文件路径
     * @param className 文件名 ( 类名 )
     * @return 执行参数
     */
    public static String[] getExecuteParams(final boolean readAll, final String path, final String className) {
        if (readAll) {
            return new String[] { "-private", "-encoding", "utf-8", "-doclet", Doclet.class.getName(),
                    path + className };
        } else {
            return new String[] { "-encoding", "utf-8", "-doclet", Doclet.class.getName(), path + className };
        }
    }

    public static void main(String[] args) {
        ExcelWriter excelWriter = null;
        WriteSheet writeSheet = EasyExcel.writerSheet("测试用例xx").build();
        try {
            excelWriter = EasyExcel.write(new File("测试用例"+System.currentTimeMillis()+".xlsx"), JavaInterface.class).build();
            // 文件路径
            final String path = "D:\\work\\ideawork\\IdeaProjects\\prescription-service\\prescription-service-share\\src\\main\\java\\com\\guahao\\med\\prescription\\share\\";
            File file = new File(path);
            if (file.isDirectory()) {
                File[] files = file.listFiles();
                for (File f:files){
                    if (f.isFile()) {
//                        System.out.println(f.getName());
                        singlePath(excelWriter, writeSheet, path, f.getName());
                    }
                }
            }
            // 打印文档信息
            //System.out.println(javaDcoData);

        } finally {
            // 千万别忘记finish 会帮忙关闭流
            if (excelWriter != null) {
                excelWriter.finish();
            }
        }
    }

    private static void singlePath(ExcelWriter excelWriter, WriteSheet writeSheet, String path, String className) {
        // 执行参数
        final String[] executeParams = JavaDocReader.getExecuteParams(true, path, className);

        // 读取文档
        ExcelWriter finalExcelWriter = excelWriter;
        String javaDcoData = JavaDocReader.readDoc(new Callback() {
            @Override
            public String callback(String path, String className, RootDoc rootDoc, ClassDoc[] classDocs) {
                StringBuffer buffer = new StringBuffer();
                buffer.append("\n\n");
                buffer.append("\n===============");
                buffer.append("\n= 读取 JavaDoc =");
                buffer.append("\n===============");
                buffer.append("\n");
                // 拼接信息
                buffer.append("\n文件路径: ").append(path + className).append("\n文件名字: ").append(className)
                        .append("\n执行参数: ").append(Arrays.toString(executeParams));

                if (classDocs != null) {
                    StringBuffer classBuffer = new StringBuffer();
                    // 循环 Class Doc 信息
                    for (ClassDoc classDoc : classDocs) {
                        classBuffer.append("\n\n");
                        classBuffer.append("\n= " + classDoc.name() + " =\n");
                        // 包名.类名
                        classBuffer.append("\n包名.类名: ").append(classDoc.toString());
                        // 类注释
                        classBuffer.append("\n类注释: ").append(classDoc.commentText());

                        // ==========
                        // = 读取方法 =
                        // ==========

                        StringBuffer methodBuffer = new StringBuffer();
                        // 获取方法 Doc 信息数组
                        MethodDoc[] methodDocs = classDoc.methods();
                        // 防止不存在方法
                        if (methodDocs.length != 0) {
                            methodBuffer.append("\n\n| 方法信息 |");
                        }
                        // 循环读取方法信息
                        for (MethodDoc methodDoc : methodDocs) {
                            methodBuffer.append("\n");
                            // 方法名
                            methodBuffer.append("\n方法名: " + methodDoc.name());
                            // 方法注释
                            methodBuffer.append("\n方法注释: " + methodDoc.commentText());
                            JavaInterface javaInterface=new JavaInterface(classDoc.name(),methodDoc.name(),methodDoc.commentText());
                            finalExcelWriter.write(Arrays.asList(javaInterface),writeSheet);
                        }
                        // 保存方法信息
                        classBuffer.append(methodBuffer);
                    }
                    // 保存类信息
                    buffer.append(classBuffer);
                }

                buffer.append("\n\n");
                buffer.append("\n===================");
                buffer.append("\n= 读取 JavaDoc 结束 =");
                buffer.append("\n===================");
                buffer.append("\n");

                // 返回文档信息
                return buffer.toString();
            }

            @Override
            public void error(Exception e) {
                //System.out.println(e);
            }
        }, path, className, executeParams);
    }
}

@ContentRowHeight(15)
@HeadFontStyle(fontHeightInPoints = 11)
@ColumnWidth(25)
class JavaInterface {
    /**
     * 类名
     */
    @ExcelProperty(value = "类名")
    private String className;
    /**
     * 方法名
     */
    @ExcelProperty("方法名")
    private String methodName;
    /**
     * 描述
     */
    @ExcelProperty(value = "描述")
    @ColumnWidth(80)
    private String desc;

    public JavaInterface(String className, String methodName, String desc) {
        this.className = className;
        this.methodName = methodName;
        this.desc = desc;
    }

    public JavaInterface() {
    }

    public String getClassName() {
        return className;
    }

    public void setClassName(String className) {
        this.className = className;
    }

    public String getMethodName() {
        return methodName;
    }

    public void setMethodName(String methodName) {
        this.methodName = methodName;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }
}
